package org.windowkit.toolkit.widget.tree;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;

public class CheckBoxTreeCellRenderer extends JLabel implements TreeCellRenderer {

    /**
	 *
	 */
	private static final long serialVersionUID = 4762366625341017182L;
	private String name;
    private boolean hasFocus;
    private boolean selected;
    private boolean checked;

    private boolean chkBoxDimsSet = false;
    private int chkBoxSide = 10;
    private final int chkBoxSpace = 5;
    private int chkBoxYoffset = 0;

    private Color checkedColor;


    CheckBoxTree tree;

    // Icons
    /** Icon used to show non-leaf nodes that aren't expanded. */
    transient protected Icon closedIcon;

    /** Icon used to show leaf nodes. */
    transient protected Icon leafIcon;

    /** Icon used to show non-leaf nodes that are expanded. */
    transient protected Icon openIcon;

    // Colors
    /** Color to use for the foreground for selected nodes. */
    protected Color textSelectionColor;

    /** Color to use for the foreground for non-selected nodes. */
    protected Color textNonSelectionColor;

    /** Color to use for the background when a node is selected. */
    protected Color backgroundSelectionColor;

    /** Color to use for the background when the node isn't selected. */
    protected Color backgroundNonSelectionColor;

    /** Color to use for the focus indicator when the node has focus. */
    protected Color borderSelectionColor;


	public CheckBoxTreeCellRenderer() {

        setCheckedColor(Color.LIGHT_GRAY);


        setLeafIcon(UIManager.getIcon("Tree.leafIcon"));
        setClosedIcon(UIManager.getIcon("Tree.closedIcon"));
        setOpenIcon(UIManager.getIcon("Tree.openIcon"));

        setTextSelectionColor(UIManager.getColor("Tree.selectionForeground"));
        setTextNonSelectionColor(UIManager.getColor("Tree.textForeground"));
        setBackgroundSelectionColor(UIManager.getColor("Tree.selectionBackground"));
        setBackgroundNonSelectionColor(UIManager.getColor("Tree.textBackground"));
        setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));


	}

	public Component getTreeCellRendererComponent(final JTree treee,
			final Object value, final boolean sel, final boolean expanded,
			final boolean leaf, final int row, final boolean hasFoc) {

        this.tree = (CheckBoxTree)treee;
        this.name = value.toString();
        this.hasFocus = hasFoc;
        this.selected = sel;

        this.setText(name);

        if(this.selected){
            setForeground(getTextSelectionColor());

        }else{
            setForeground(getTextNonSelectionColor());
        }

        if(tree.isNodeChecked((DefaultMutableTreeNode)value)){
            this.checked = true;
        }else{
            this.checked = false;
        }

        setComponentOrientation(tree.getComponentOrientation());


        //enabled tree
        if(tree.isEnabled()){
            setEnabled(true);
            if(leaf){
                this.setIcon(getLeafIcon());
            }else if(expanded){
                this.setIcon(getOpenIcon());
            }else{
                this.setIcon(getClosedIcon());
            }
        }else{
            //disabled tree
            setEnabled(false);
            if(leaf){
                this.setDisabledIcon(getLeafIcon());
            }else if(expanded){
                this.setDisabledIcon(getOpenIcon());
            }else{
                this.setDisabledIcon(getClosedIcon());
            }
        }


        //set the non-selected bg color to be the same as the tree
        setBackgroundNonSelectionColor(tree.getBackground());


		return this;
	}


	/**
	 * Paints the value.  The background is filled based on selected.
	 */
	@Override
    public void paint(Graphics g) {
        g=g.create();

        //determine the dimensions of our check box if we havnt yet
        if(!chkBoxDimsSet){
            updateCheckBoxDims();
            chkBoxDimsSet = true;
        }

        drawCheckBox(g);

        Color bColor;

	    if(selected) {
	        bColor = getBackgroundSelectionColor();
	    } else {
	        bColor = getBackgroundNonSelectionColor();
	        if(bColor == null) {
				bColor = tree.getBackground();
			}
	    }

        //color the filled rectangle behind the label
	    int imageOffset = -1;
	    if(bColor != null) {
	        imageOffset = getLabelStart();
	        g.setColor(bColor);
	        if(getComponentOrientation().isLeftToRight()) {
	            g.fillRect(imageOffset, 0, getWidth() - imageOffset - getCheckBoxOffset(),
	                    getHeight());
	        } else {
	            g.fillRect(0, 0, getWidth() - imageOffset - getCheckBoxOffset(),
	                    getHeight());
	        }
	    }


        //draw the rectangle around the label
	    if (hasFocus) {

	        if(getComponentOrientation().isLeftToRight()) {
                paintFocus(g, imageOffset, 0,
                        getWidth() - imageOffset - getCheckBoxOffset(), getHeight());

	        } else {
                paintFocus(g, 0, 0,
                        getWidth() - imageOffset - getCheckBoxOffset(), getHeight());
	        }
	    }

        super.paint(g);
	}

	private void paintFocus(final Graphics g, final int x, final int y, final int w, final int h) {
		Color bColor = getBorderSelectionColor();
		g.setColor(bColor);
        g.drawRect(x, y, w - 1, h - 1);
//
//		Color       bsColor = getBorderSelectionColor();
//
//		if (bsColor != null && (selected || !drawDashedFocusIndicator)) {
//			g.setColor(bsColor);
//			g.drawRect(x, y, w - 1, h - 1);
//		}
//		if (drawDashedFocusIndicator) {
//			Color color;
//			if (selected) {
//				color = getBackgroundSelectionColor();
//			} else {
//				color = getBackgroundNonSelectionColor();
//				if(color == null) {
//					color = getBackground();
//				}
//			}
//
//			if (treeBGColor != color) {
//				treeBGColor = color;
//				focusBGColor = new Color(~color.getRGB());
//			}
//			g.setColor(focusBGColor);
//			BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
//		}
	}



//	@Override
//	public void setBackground(Color color) {
//	    if(color instanceof ColorUIResource)
//	        color = null;
//	    super.setBackground(color);
//	}

    private void drawCheckBox(final Graphics g){

        g.setColor(Color.BLACK);
        g.drawRoundRect(0, chkBoxYoffset, chkBoxSide, chkBoxSide,
                (int)(chkBoxSide * .42), (int)(chkBoxSide * .42));

        if(checked){
            g.setColor(getCheckedColor());
            g.fillRect(0 + 2, chkBoxYoffset + 2, chkBoxSide - 3, chkBoxSide - 3);
        }

        g.translate(getCheckBoxOffset(), 0);

    }

    public void updateCheckBoxDims(){
        Font font = getFont();
        if(font != null){
            chkBoxSide = font.getSize();
            chkBoxYoffset = (getHeight() - chkBoxSide)/2;
        }
    }

    @Override
    public void setFont(Font font) {
        if(font instanceof FontUIResource){
            font = null;
        }
        super.setFont(font);
        updateCheckBoxDims();
    }

    @Override
    public Font getFont() {
        Font font = super.getFont();
        if (font == null && tree != null) {
            // Strive to return a non-null value, otherwise the html support
            // will typically pick up the wrong font in certain situations.
            font = tree.getFont();
        }
        return font;
    }


	private int getLabelStart() {
		Icon currentI = this.getIcon();
		if(currentI != null && this.getText() != null) {
			return currentI.getIconWidth() + Math.max(0, this.getIconTextGap() - 1);
		}
		return 0;
	}

    private int getCheckBoxOffset(){
        return chkBoxSide + chkBoxSpace;
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension dim = super.getPreferredSize();
        if(dim != null){
            dim = new Dimension(dim.width + getCheckBoxOffset() + 5,
                    dim.height);
        }
        return dim;

    }

    /**
     *
     * @return The size of the side of the check box.
     */
    public int getCheckBoxSize(){
        return chkBoxSide;
    }

    /**
     *
     * @return The Y offset for the location of the checkbox.
     */
    public int getCheckBoxYOffset(){
        return chkBoxYoffset;
    }

    /**
     * @return Returns the closedIcon.
     */
    public Icon getClosedIcon() {
        return closedIcon;
    }

    /**
     * @param closedIcon The closedIcon to set.
     */
    public void setClosedIcon(final Icon closedIcon) {
        this.closedIcon = closedIcon;
    }

    /**
     * @return Returns the leafIcon.
     */
    public Icon getLeafIcon() {
        return leafIcon;
    }

    /**
     * @param leafIcon The leafIcon to set.
     */
    public void setLeafIcon(final Icon leafIcon) {
        this.leafIcon = leafIcon;
    }

    /**
     * @return Returns the openIcon.
     */
    public Icon getOpenIcon() {
        return openIcon;
    }

    /**
     * @param openIcon The openIcon to set.
     */
    public void setOpenIcon(final Icon openIcon) {
        this.openIcon = openIcon;
    }

    /**
     * @return Returns the backgroundNonSelectionColor.
     */
    public Color getBackgroundNonSelectionColor() {
        return this.backgroundNonSelectionColor;
    }

    /**
     * @param backgroundNonSelectionColor The backgroundNonSelectionColor to set.
     */
    public void setBackgroundNonSelectionColor(final Color backgroundNonSelectionColor) {
        this.backgroundNonSelectionColor = backgroundNonSelectionColor;
    }

    /**
     * @return Returns the backgroundSelectionColor.
     */
    public Color getBackgroundSelectionColor() {
        return backgroundSelectionColor;
    }

    /**
     * @param backgroundSelectionColor The backgroundSelectionColor to set.
     */
    public void setBackgroundSelectionColor(final Color backgroundSelectionColor) {
        this.backgroundSelectionColor = backgroundSelectionColor;
    }

    /**
     * @return Returns the borderSelectionColor.
     */
    public Color getBorderSelectionColor() {
        return borderSelectionColor;
    }

    /**
     * @param borderSelectionColor The borderSelectionColor to set.
     */
    public void setBorderSelectionColor(final Color borderSelectionColor) {
        this.borderSelectionColor = borderSelectionColor;
    }

    /**
     * @return Returns the textNonSelectionColor.
     */
    public Color getTextNonSelectionColor() {
        return textNonSelectionColor;
    }

    /**
     * @param textNonSelectionColor The textNonSelectionColor to set.
     */
    public void setTextNonSelectionColor(final Color textNonSelectionColor) {
        this.textNonSelectionColor = textNonSelectionColor;
    }

    /**
     * @return Returns the textSelectionColor.
     */
    public Color getTextSelectionColor() {
        return textSelectionColor;
    }

    /**
     * @param textSelectionColor The textSelectionColor to set.
     */
    public void setTextSelectionColor(final Color textSelectionColor) {
        this.textSelectionColor = textSelectionColor;
    }

    /**
     * @return Returns the checkedColor.
     */
    public Color getCheckedColor() {
        return checkedColor;
    }

    /**
     * @param checkedColor The checkedColor to set.
     */
    public void setCheckedColor(final Color checkedColor) {
        this.checkedColor = checkedColor;
    }



}
